package com.gitee.wsl.struct.command.model.parameters

import com.gitee.wsl.struct.command.completion.CompletionCandidates
import com.gitee.wsl.struct.command.context.Context
import com.gitee.wsl.struct.command.model.ParameterHolder
import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

interface BaseOption<T,D>{

    /**
     * The description of this argument.
     *
     * It's usually better to leave this null and describe options in the usage line of the command instead.
     */
    fun help(context: Context): String

    /** Extra information about this argument to pass to the help formatter. */
    val helpTags: Map<String, String>

    /** Optional set of strings to use when the user invokes shell autocomplete on a value for this argument. */
    val completionCandidates: CompletionCandidates get() = CompletionCandidates.None

    /** Information about this argument for the help output. */
    fun parameterHelp(context: Context): D?

    /**
     * Called after all of a command's parameters have been [finalize]d to perform validation of the final value.
     */
    fun postValidate(context: Context)

    /**
     * Called after this command's argv is parsed to transform and store the argument's value.
     *
     * You cannot refer to other parameter values during this call, since they might not have been
     * finalized yet.
     *
     * @param context The context for this parse
     * @param values A possibly empty list of values provided to this argument.
     */
    fun finalize(context: Context, values: T)
}

/** An argument that functions as a property delegate */
interface BaseOptionDelegate<A,B,R: ParameterHolder,out T> :
    BaseOption<A, B>,
    ReadOnlyProperty<R, T>,
    PropertyDelegateProvider<R, ReadOnlyProperty<R, T>> {
    /**
     * The value for this argument.
     *
     * @throws IllegalStateException if this property is accessed before [finalize] is called.
     */
    val value: T

    override fun getValue(thisRef: R, property: KProperty<*>): T = value

}